﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using repliback4.Net.Protocol.Messages;
using repliback4.Net.Protocol.Messages.Attributes;
using Tools.Debugging;


namespace repliback4.Xml {
    public class TagCreateException : Exception {
        public TagCreateException ( String message ) : base( message ) { }
    }

    public enum TagRegistryErrorCodes { None, UnknownTag }
    public class TagRegistryException : Exception {
        protected TagRegistryErrorCodes errorCode = TagRegistryErrorCodes.None;
        public TagRegistryErrorCodes ErrorCode {
            get { return this.errorCode; }
        }
        public TagRegistryException ( String message ) : base( message ) { }
        public TagRegistryException ( String message, TagRegistryErrorCodes errorCode )
            : base( message ) {
            this.errorCode = errorCode;
        }
    }

    public class TagRegistry {
        protected Dictionary<XmlQualifiedName, Type> table = new Dictionary<XmlQualifiedName, Type>( );
        public TagRegistry ( ) { }

        public void Register ( Type tagClass ) {
            RequestTag[] _tag = ( RequestTag[] ) tagClass.GetCustomAttributes( typeof( RequestTag ), false );
            if ( _tag.Length == 1 ) {
                this.Register( _tag[0], tagClass );
            } else {
                throw new Exception( "you are trying to regiter invalid type" );
            }

        }

        protected void Register ( RequestTag tag, Type tagClass ) {
            XmlQualifiedName name = new XmlQualifiedName( tag.Name, tag.Namespace );
            table.Add( name, tagClass );
        }

        public Type GetTagType ( XmlQualifiedName xqName ) {
            if ( !this.table.ContainsKey( xqName ) ) {
                throw new TagRegistryException( String.Format( "unknown tag identified by {0}", xqName ), TagRegistryErrorCodes.UnknownTag );
            }
            return this.table[xqName];
        }

        public Type GetTagType ( String name, String ns ) {
            return this.GetTagType( new XmlQualifiedName( name, ns ) );
        }

        public ReplibackTag GetTag ( XmlNode tagElement ) {
            //try
            //{
            Type t = this.GetTagType( tagElement.LocalName, tagElement.NamespaceURI );

            ConstructorInfo cInfo = t.GetConstructor( new Type[] { typeof( XmlElement ) } );
            if ( cInfo == null ) {
                throw new TagCreateException( String.Format( "cant get contructor for [{0}]", t.FullName ) );
            }

            //
            ReplibackTag r = cInfo.Invoke( new Object[] { tagElement } ) as ReplibackTag;
            r.Registry = this;
            //ReplibackTag r = cInfo.Invoke( new Object[] { tagElement, this } ) as ReplibackTag;
            return r;
            //}
            //catch (Exception e)
            //{
            //    Logger.DebugFormat(this, "GetTagType exception: [{0}]", e.Message);
            //    throw e;
            //}

        }
    }
}
